﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Description; //WS的描述
using System.CodeDom;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Configuration;
using System.Reflection;
using System.Net;
using System.IO;
using log4net;

namespace WHYHLWebservices
{
    public class YHLWebService
    {
        public string webServiceUrl;
        
        public void TestWebService()
        {   
                webServiceUrl = ConfigurationManager.AppSettings["yhlWebService"];  //获取配置文件的WebService地址

                if (!string.IsNullOrEmpty(webServiceUrl))  //如果webService地址不为空，则进行WebService的动态调用  
                {  
                    string strTestXml="11111";
                    String strRsp = InvokeWebservice(webServiceUrl, "jari", "Service1",
                   "SendPassCarInfo_withImg", new object[] { strTestXml }).ToString();
   
                }
        }
        /// 根据指定的信息，调用远程WebService方法    
        /// </summary>    
        /// <param name="url">WebService的http形式的地址</param>    
        /// <param name="nameSpace">欲调用的WebService的命名空间</param>    
        /// <param name="classname">欲调用的WebService的类名（不包括命名空间前缀）</param>    
        /// <param name="methodname">欲调用的WebService的方法名</param>    
        /// <param name="args">参数列表</param>  
        /// <returns>WebService的执行结果</returns>    
        public string InvokeWebservice(string url, string nameSpace, string classname, string methodname,object[] args)
        {
            try
            {
                //1.使用WebClient 下载WSDL信息  
                WebClient wc = new WebClient();
                Stream stream = wc.OpenRead(url + "?WSDL");

                //2.创建和格式化WSDL文档  
                ServiceDescription srvDesc = ServiceDescription.Read(stream);

                //3. 创建客户端代理代理类  
                ServiceDescriptionImporter srvDescInporter = new ServiceDescriptionImporter();
                srvDescInporter.ProtocolName = "Soap";//指定访问协议  
                srvDescInporter.Style = ServiceDescriptionImportStyle.Client;//生成客户端代理，默认。  
                srvDescInporter.AddServiceDescription(srvDesc, "", ""); //添加WSDL文档。  

                //4 .使用 CodeDom 编译客户端代理类。  
                CodeNamespace codeNamespce = new CodeNamespace(nameSpace);
                CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
                codeCompileUnit.Namespaces.Add(codeNamespce);
                srvDescInporter.Import(codeNamespce, codeCompileUnit);

                CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");

                //表示用于调用编译器的参数。  
                System.CodeDom.Compiler.CompilerParameters parameter = new System.CodeDom.Compiler.CompilerParameters();
                parameter.GenerateExecutable = false;   //设置是否生成可执行文件。  
                parameter.GenerateInMemory = true;      //设置是否在内存中生成输出。  
                parameter.ReferencedAssemblies.Add("System.dll");   //ReferencedAssemblies  获取当前项目所引用的程序集。  
                parameter.ReferencedAssemblies.Add("System.XML.dll");
                parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
                parameter.ReferencedAssemblies.Add("System.Data.dll");

                //获取从编译器返回的编译结果。  
                System.CodeDom.Compiler.CompilerResults cr = provider.CompileAssemblyFromDom(parameter, codeCompileUnit);
                if (true == cr.Errors.HasErrors)
                {
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();
                    foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
                    {
                        sb.Append(ce.ToString());
                        sb.Append(System.Environment.NewLine);
                    }
                    throw new Exception(sb.ToString());
                }

                //获取已编译的程序集，然后通过反射进行动态调用。  
                System.Reflection.Assembly assembly = cr.CompiledAssembly;
                Type t = assembly.GetType(nameSpace + "." + classname, true, true); // 如果在前面为代理类添加了命名空间，此处需要将命名空间添加到类型前面。  
                object obj = Activator.CreateInstance(t);
                System.Reflection.MethodInfo mi = t.GetMethod(methodname);
                return (string)mi.Invoke(obj, args);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.InnerException.Message, new Exception(ex.InnerException.StackTrace));
            }
        }
    
    
    }
}
